package squirrel

import scala.util.Success

import scala.util.Try

case class SqlSelectAst(from: SqlFrom,
                        columns: Option[Seq[SqlColumn]] = None,
                        where: Option[SqlWhere] = None,
                        limit: Option[Int] = None,
                        offset: Option[Int] = None) {
  def toSQL: Try[ParameterizedSQL] = {
    val columnsSql = buildColumns(columns.getOrElse(Seq()))
    val w = where.getOrElse(SqlWhereEmpty)
    Seq(from.toSQL, columnsSql, w.toSQL) match {
      case Seq(Success(fromSql), Success(colSql), Success(whereSql)) =>
        val base = s"SELECT ${colSql.sql} FROM ${fromSql.sql}"
        val sb = new StringBuilder(base)
        if (!whereSql.sql.isEmpty) {
          sb ++= s" WHERE ${whereSql.sql}"
        }
        if (limit.isDefined) {
          sb ++= s" LIMIT ${limit.get}"
        }
        if (offset.isDefined) {
          sb ++= s" OFFSET ${offset.get}"
        }
        val sql = sb.toString()
        val args = colSql.args ++ fromSql.args ++ whereSql.args
        val p = ParameterizedSQL(sql, args)
        Success(p)
      case err => err.find(_.isFailure).get
    }
  }

  def buildColumns(columns: Seq[SqlColumn]): Try[ParameterizedSQL] = {
    if (columns.isEmpty) {
      Success(ParameterizedSQL("*", Seq()))
    } else {
      val all = columns.map(_.toSQL)
      all find (_.isFailure) match {
        case Some(f) => f
        case None =>
          val s = all.map(_.get)
          val sql = s.map(_.sql).mkString(", ")
          val args = s.flatMap(_.args)
          Success(ParameterizedSQL(sql, args))
      }
    }
  }
}
